package org.niugang.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

@Configuration
/*
 * 在当前应用程序上下文中启用授权服务器(即AuthorizationEndpoint和TokenEndpoint)的便利注释，
 * 它必须是一个DispatcherServlet上下文。服务器的许多特性可以通过使用AuthorizationServerConfigurer类型的@
 * bean来定制(例如，通过扩展AuthorizationServerConfigurerAdapter)。用户负责使用正常的Spring安全特性(
 * 
 * @EnableWebSecurity等)来保护授权端点(/oauth/授权)，但是令牌端点(/oauth/
 * Token)将通过客户端凭证上的HTTP基本身份验证自动获得。
 * 客户端必须通过一个或多个AuthorizationServerConfigurers提供一个ClientDetailsService来注册。
 */
/**
 * 
 * @ClassName: AuthorizationServerConfiguration
 * @Description:认证服务器
 * @author: niugang
 * @date: 2018年9月5日 下午8:10:29
 * @Copyright: 863263957@qq.com. All rights reserved.
 *
 */
@EnableAuthorizationServer
/**
 程序需要对外暴露获取Token的api和验证Token的API,所以程序也是一个资源服务器
 */
@EnableResourceServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
	// 模拟第三方调用api
	private static final String DEMO_RESOURCE_ID = "api";

	/**
	 * 这个Bean是在WebSecurityConfigurerAdapter中定义的
	 */
	@Autowired
	@Qualifier("authenticationManagerBean")
	private AuthenticationManager authenticationManager;
	
	
	@Autowired
	private UserDetailsService userDetailsService;

	@Autowired
	private WebResponseExceptionTranslator customWebResponseExceptionTranslator;

	/**
	 * accessTokenValiditySeconds:设置token无效时间,秒
	 * refreshTokenValiditySeconds：设置refresh_token无效时间秒
	 */
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		// 配置两个客户端,一个用于password认证一个用于client认证
		// 默认token的有效期为12小时
		clients.inMemory().
				// 基于客户端认证的
				withClient("client_1")
				.resourceIds(DEMO_RESOURCE_ID).authorizedGrantTypes("client_credentials", "refresh_token")
				// .refreshTokenValiditySeconds(3600).accessTokenValiditySeconds(20)
				.scopes("select").authorities("client").secret("123456")
				// 基于密码的
				.and().withClient("client_2")
				.resourceIds(DEMO_RESOURCE_ID).autoApprove(true).authorizedGrantTypes("password", "refresh_token").scopes("server")
				//// *.refreshTokenValiditySeconds(3600).accessTokenValiditySeconds(60)*/;
				.authorities("client")
				// 基于CODE
				.secret("123456").and().withClient("client_3")
				.resourceIds(DEMO_RESOURCE_ID).authorizedGrantTypes("authorization_code", "refresh_token")
				.scopes("select").authorities("client").secret("123456");

	}

	/**
	 * 配置授权Token的节点和Token的服务
	 * @param endpoints
	 * @throws Exception
	 */
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints // token管理策略 
				.tokenStore(jwtTokenStore()).tokenEnhancer(jwtAccessTokenConverter())
				// 开起密码验证
				.authenticationManager(authenticationManager)
				// 配置获取用户信息的接口
				// 密码模式需要在数据库中进行认证
				.userDetailsService(userDetailsService);
		// 错误异常
		endpoints.exceptionTranslator(customWebResponseExceptionTranslator);
	}

	/**
	 *  配置Token节点的安全策略
	 * @param oauthServer
	 * @throws Exception
	 */
	@Override
	public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
		// 允许表单认证
		oauthServer.allowFormAuthenticationForClients();
	}

	@Bean
	public TokenStore jwtTokenStore() {
		return new JwtTokenStore(jwtAccessTokenConverter());
	}

	//
	@Bean
	protected JwtAccessTokenConverter jwtAccessTokenConverter() {
		JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
		jwtAccessTokenConverter.setSigningKey("ng123456");
		return jwtAccessTokenConverter;
	}
}
